/*
 *	@file	pgear_save.c
 *	@brief	ポケギアセーブデータ
 *	@data	07.08.03
 *	@author	Miyuki Iwasawa
 */


#include "common.h"
#include "itemtool/itemsym.h"
#include "tel/pmtel_number.h"
#include "savedata/savedata.h"
#include "savedata/pgear_sv.h"

#define __PGEAR_SV_UTIL_H_GLOBAL
#include "savedata/pgear_sv_util.h"
#include "savedata/pgear_sv_local.h"

////////////////////////////////////////////////////////////////////////
//ローカル
static void PMTelSv_Clear(PMTEL_SAVE* ps);

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	ポケギアセーブデータサイズ取得
 */
int PGearSv_GetWorkSize(void)
{
	return sizeof(PGEAR_SAVE);
}
/**
 *	@brief	セーブデータブロックへのポインタを取得
 */
PGEAR_SAVE* SaveData_GetPGearSave(SAVEDATA* sv)
{
	return SaveData_Get(sv,GMDATA_ID_PGEAR_SAVE);
}

/**
 *	@brief	セーブデータブロックへのポインタを取得
 */
PMTEL_SAVE* SaveData_GetPMTelSave(SAVEDATA* sv)
{
	return PGearSv_GetTelDataP(SaveData_Get(sv,GMDATA_ID_PGEAR_SAVE));
}


/**
 *	@brief	ポケギアセーブデータクリア
 */
void PGearSv_Clear(PGEAR_SAVE* sv)
{
	int i;

	MI_CpuClear8(sv,sizeof(PGEAR_SAVE));

	sv->mode = PGMODE_ID_TEL;
	sv->skin = PGSKIN_ID_DEFAULT;
	sv->map_aff = PGMAFF_MODE_NORMAL;
	sv->radio_chx = sv->radio_chy = 128;
	sv->aopen = 0;
	sv->map_open = 0;

	PGearSv_TelBookAllClear(sv);

	PMTelSv_Clear(&sv->tel);
}

/**
 *	@brief	ポケギアデータ　初期データ
 */
void PGearSv_Init(PGEAR_SAVE* sv)
{
	PGearSv_Clear(sv);
}

/**
 *	@brief	マーカーブロックへのポインタを取得する
 */
MARKER_BLOCK* PGearSv_GetMarkerBlockP(PGEAR_SAVE* sv)
{
	return &(sv->marker);
}

/**
 *	@brief	ポケギア　モード取得
 */
PG_MODE_ID PGearSv_GetMode(PGEAR_SAVE* sv)
{
	return sv->mode;
}

/**
 *	@brief	ポケギア　モードセット
 */
void PGearSv_SetMode(PGEAR_SAVE* sv,PG_MODE_ID mode)
{
	sv->mode = mode;
}

/**
 *	@brief	ポケギア　アプリオープンフラグセット
 */
void PGearSv_SetAppOpenFlag(PGEAR_SAVE* sv,PGAPP_OPEN_FLAG flag)
{
	switch(flag){
	case 0:
		sv->aopen = 0;
		break;
	case 1:
		sv->aopen |= PGAPP_OPEN_MAP;
		break;
	case 2:
		sv->aopen |= PGAPP_OPEN_RADIO;
		break;
	}
}

/**
 *	@brief	ポケギア　アプリオープンフラグ取得
 */
u8 PGearSv_GetAppOpenFlag(PGEAR_SAVE* sv)
{
	return sv->aopen;
}

/**
 *	@brief	ポケギア　マップオープンレベルセット
 */
void PGearSv_SetMapOpenLevel(PGEAR_SAVE* sv,u8 level)
{
	if(level < 3){
		sv->map_open = level;
	}
}

/**
 *	@brief	ポケギア　マップオープンフラグ取得
 */
u8 PGearSv_GetMapOpenLevel(PGEAR_SAVE* sv)
{
	return sv->map_open;
}

/**
 *	@brief	ポケギア　スキンID取得
 */
PG_SKIN_ID PGearSv_GetSkin(PGEAR_SAVE* sv)
{
	return sv->skin;
}

/**
 *	@brief	ポケギア　スキンIDセット
 */
void PGearSv_SetSkin(PGEAR_SAVE* sv,PG_SKIN_ID skin)
{
	sv->skin = skin;
}

/**
	@brief	ポケギア　スキン取得フラグセット
 */
void PGearSv_SetSkinFlag(PGEAR_SAVE* sv,PG_SKIN_ID id)
{
	int i;
	u16	flag = 1;
	for(i = 0;i < id;i++){
		flag <<= 1;
	}
	sv->skin_f |= flag;
}

/**
 *	@brief	ポケギア　指定したIDのスキンが取得されているかどうか？
 */
BOOL PGearSv_GetSkinFlag(PGEAR_SAVE* sv,PG_SKIN_ID id)
{
	int i;
	u16	flag = 1;
	for(i = 0;i < id;i++){
		flag <<= 1;
	}
	return (sv->skin_f & flag);
}

/**
 *	@brief	ポケギア　スキンの取得フラグをまとめてu16型で取得
 */
u16	PGearSv_GetSkinFlagAll(PGEAR_SAVE* sv)
{
	return (u16)sv->skin_f;
}

/**
	@brief	ポケギア　新スキン取得フラグ On/Off
 */
void PGearSv_SetNewSkinFlag(PGEAR_SAVE* sv,PG_SKIN_ID id,BOOL state)
{
	int i;
	u16	flag = 1;

	for(i = 0;i < id;i++){
		flag <<= 1;
	}
	if(state){
		sv->skin_nf |= flag;
	}else{
		sv->skin_nf ^= flag;
	}
}

/**
 *	@brief	ポケギア　指定したIDの新スキン取得フラグが有効かどうか？
 */
BOOL PGearSv_GetNewSkinFlag(PGEAR_SAVE* sv,PG_SKIN_ID id)
{
	int i;
	u16	flag = 1;
	for(i = 0;i < id;i++){
		flag <<= 1;
	}
	return (sv->skin_nf & flag);
}

/**
 *	@brief	ポケギア　新スキン取得フラグをまとめてu16型で取得
 */
u16	PGearSv_GetNewSkinFlagAll(PGEAR_SAVE* sv)
{
	return (u16)sv->skin_nf;
}

/**
 *	@brief	ポケギア　マップアフィン取得
 */
PG_MAPAFF_MODE PGearSv_GetMapAff(PGEAR_SAVE* sv)
{
	return sv->map_aff;
}

/**
 *	@brief	ポケギア　マップアフィンモードセット
 */
void PGearSv_SetMapAff(PGEAR_SAVE* sv,PG_MAPAFF_MODE aff)
{
	sv->map_aff = aff;
}

/**
 *	@brief	ポケギア　ラジオ選局カーソル位置セット
 */
void PGearSv_SetRadioChSelectPos(PGEAR_SAVE* sv,u8 x,u8 y)
{
	sv->radio_chx = x;
	sv->radio_chy = y;
}

/**
 *	@brief	ポケギア　ラジオ選局カーソル位置取得
 */
void PGearSv_GetRadioChSelectPos(PGEAR_SAVE* sv,s16* x,s16* y)
{
	*x = sv->radio_chx;
	*y = sv->radio_chy;
}

/**
 *	@brief	ポケギア　電話帳　登録数取得
 */
u8 PGearSv_GetTelBookEntryNum(PGEAR_SAVE* sv)
{
	u8 i;

	for(i = 0;i < PMTEL_NUMBER_MAX;i++){
		if(sv->tbook[i] == PMTEL_NUMBER_NULL){
			return i;
		}
	}
	return PMTEL_NUMBER_MAX;
}

/*
 *	@brief	ポケギア　電話帳　重複登録チェック用
 *
 *	@retval PMTEL_NUMBER_NULL：未登録
 *	@retval そのた：登録済み(登録されているナンバー)
 */
PMTEL_NUMBER PGearSv_IsTelNumberEntry(PGEAR_SAVE* sv,PMTEL_NUMBER_ID id)
{
	PMTEL_NUMBER i;

	for(i = 0;i < PMTEL_NUMBER_MAX;i++){
		if(sv->tbook[i] == id){
			return i;
		}
		if(sv->tbook[i] == PMTEL_NUMBER_NULL){
			return PMTEL_NUMBER_NULL;
		}
	}
	return PMTEL_NUMBER_NULL;
}

/**
 *	@brief	ポケギア　電話帳　新規登録
 */
void PGearSv_AddTelNumber(PGEAR_SAVE* sv,PMTEL_NUMBER_ID id)
{
	PMTEL_NUMBER num;

	if(id >= PMTEL_NUMBER_MAX){
		OS_Printf("\nTelBook %d <= 不正なIDを電話帳に登録しようとしました\n",id);
		GF_ASSERT(0);
		return;
	}
	if(PGearSv_IsTelNumberEntry(sv,id) != PMTEL_NUMBER_NULL){
		OS_Printf("\nTelBook %d <= 登録済みのIDを電話帳に登録しようとしました\n",id);
		return;
	}
	//一番最後に登録
	num = PGearSv_GetTelBookEntryNum(sv);
	sv->tbook[num] = id;
}

/*
 *	@brief	ポケギア　電話帳　登録アドレスをまとめてAllocした
 *			PMTEL_NUMBER型(u8)のバッファに取得
 *
 *	＊内部でメモリをAllocするので、要らなくなったらsys_FreeMemoryEz()で解放すること！
 */
PMTEL_NUMBER* PGearSv_GetTelBook(PGEAR_SAVE* sv,int heapID)
{
	PMTEL_NUMBER* buf;
	u32	siz;

	siz = sizeof(PMTEL_NUMBER)*PGearSv_GetTelBookEntryNum(sv);
	buf = sys_AllocMemory(heapID,siz);
	MI_CpuCopy8(sv->tbook,buf,siz);

	return buf;
}

/*
 *	@brief	ポケギア　電話帳　登録アドレスの並びを書換え
 *
 *	@param	src	PMTEL_NUMBER型の配列
 *	@param	num	書換え項目数
 */
void PGearSv_PutTelBook(PGEAR_SAVE* sv,PMTEL_NUMBER* src,u8 num)
{
	//PMTEL_NUMBER型がu8でなくなったら、処理を変える必要アリ
	MI_CpuFill8(sv->tbook,PMTEL_NUMBER_NULL,PMTEL_NUMBER_MAX);

	if(num >= PMTEL_NUMBER_MAX){
		num = PMTEL_NUMBER_MAX;
	}
	MI_CpuCopy8(src,sv->tbook,num);
}

/*
 *	@brief	全電話帳データをクリアする(おかあさんだけに戻す)
 */
void PGearSv_TelBookAllClear(PGEAR_SAVE* sv)
{
	MI_CpuFill8( sv->tbook, PMTEL_NUMBER_NULL,PMTEL_NUMBER_MAX);
	sv->tbook[0] = PMTEL_NUMBER_MAMA;	//初期状態でおかあさんは登録済み
}

/**
 *	@brief	電話セーブデータポインタ取得
 */
PMTEL_SAVE* PGearSv_GetTelDataP(PGEAR_SAVE* sv)
{
	return &(sv->tel);
}

/**
 *	@brief	電話登録者個人ステータスクリア
 */
static void PMTelSv_StatusClear(PMTEL_SV_STATUS* ps)
{
	ps->revenge_f = FALSE;
	ps->item_f = FALSE;
	ps->priority = 1;
	ps->item = ITEM_DUMMY_DATA;
}

/**
 *	@brief	電話データクリア
 */
static void PMTelSv_Clear(PMTEL_SAVE* ps)
{
	int i;

	MI_CpuClear8(ps,sizeof(PMTEL_SAVE));

	for(i = 0;i < PMTEL_NUMBER_MAX;i++){
		PMTelSv_StatusClear(&ps->status[i]);
	}
	ps->takenori_ct = PMTEL_TAKENORI_CT_DEF;
}

/**
 *	@brief	着信予約　セット
 */
void PMTelSv_CallReserveSet(PMTEL_SAVE* ps,PMTEL_RESERVE_ID id)
{
	u8 ofs_buf,ofs_bit;

	if(id >= PMTEL_RESERVE_ID_MAX){
		GF_ASSERT_MSG(0,"電話着信予約 iD %d が不正\n",id);
		return;
	}
	ofs_buf = id/8;
	ofs_bit = id%8;

	ps->reserve[ofs_buf] |= (0x01<<ofs_bit);
}

/**
 *	@brief	着信予約　リセット
 */
void PMTelSv_CallReserveReset(PMTEL_SAVE* ps,PMTEL_RESERVE_ID id)
{
	u8 ofs_buf,ofs_bit;

	if(id >= PMTEL_RESERVE_ID_MAX){
		GF_ASSERT_MSG(0,"電話着信予約リセット ID %d が不正\n",id);
		return;
	}
	ofs_buf = id/8;
	ofs_bit = (0x01 << (id%8));

	if(ps->reserve[ofs_buf] & ofs_bit){
		ps->reserve[ofs_buf] ^= ofs_bit;
	}
}

/**
 *	@brief	着信予約状態取得
 */
BOOL PMTelSv_CallReserveCheck(PMTEL_SAVE* ps,PMTEL_RESERVE_ID id)
{
	u8 ofs_buf,ofs_bit;

	if(id >= PMTEL_RESERVE_ID_MAX){
		GF_ASSERT_MSG(0,"電話着信予約チェック ID %d が不正\n",id);
		return FALSE;
	}
	ofs_buf = id/8;
	ofs_bit = id%8;

	return (ps->reserve[ofs_buf] >> ofs_bit) & 0x01;
}

/*
 *	@brief	再戦フラグセット/リセット
 */
void PMTelSv_RevengeFlagSet(PMTEL_SAVE* ps,PMTEL_NUMBER_ID id,BOOL set)
{
	if(id >= PMTEL_NUMBER_MAX){
		OS_Printf("\nRevengeFlagSet %d <= 不正なIDが指定されました\n",id);
		GF_ASSERT(0);
		return;
	}
	ps->status[id].revenge_f = set;
}

/*
 *	@brief	再戦フラグ取得
 */
BOOL PMTelSv_RevengeFlagGet(PMTEL_SAVE* ps,PMTEL_NUMBER_ID id)
{
	if(id >= PMTEL_NUMBER_MAX){
		OS_Printf("\nRevengeFlagGet %d <= 不正なIDが指定されました\n",id);
		GF_ASSERT(0);
		return FALSE;
	}
	return ps->status[id].revenge_f;
}

/*
 *	@brief	アイテムイベントフラグセット/リセット
 */
void PMTelSv_ItemEvDataSet(PMTEL_SAVE* ps,PMTEL_NUMBER_ID id,u16 itemno)
{
	if(id >= PMTEL_NUMBER_MAX){
		OS_Printf("\nRevengeFlagSet %d <= 不正なIDが指定されました\n",id);
		GF_ASSERT(0);
		return;
	}
	ps->status[id].item = itemno;
	if(itemno == ITEM_DUMMY_DATA){
		ps->status[id].item_f = FALSE;
	}else{
		ps->status[id].item_f = TRUE;
	}
}

/*
 *	@brief	アイテムイベントデータ取得
 *
 *	@return	イベント用にセットされたアイテムNo
 *
 *	＊ITEM_DUMMY_DATA が返されたらイベントが設定されていない
 */
u16 PMTelSv_ItemEvDataGet(PMTEL_SAVE* ps,PMTEL_NUMBER_ID id)
{
	if(id >= PMTEL_NUMBER_MAX){
		OS_Printf("\nRevengeFlagGet %d <= 不正なIDが指定されました\n",id);
		GF_ASSERT(0);
		return ITEM_DUMMY_DATA;
	}
	if(!ps->status[id].item_f){
		return ITEM_DUMMY_DATA;
	}
	return ps->status[id].item;
}

/**
 *	@brief	貯金金額操作
 *
 *	@param	command	(PMTEL_DEPOSIT_GET,PMTEL_DEPOSIT_SET,PMTEL_DEPOSIT_ADD,PMTEL_DEPOSIT_SUB)
 *
 *	@return	操作後の貯金金額
 */
u32 PMTelSv_DepositControl(PMTEL_SAVE* ps,PMTEL_DEPOSIT_COMMAND command,u32 param)
{
	switch(command){
	case PMTEL_DEPOSIT_SET:
		ps->deposit = param;
		break;
	case PMTEL_DEPOSIT_ADD:
		ps->deposit += param;
		if(ps->deposit > PMTEL_DEPOSIT_MAX){
			ps->deposit  = PMTEL_DEPOSIT_MAX;
		}
		break;
	case PMTEL_DEPOSIT_SUB:
		if(ps->deposit < param){
			ps->deposit = 0;
		}else{
			ps->deposit -= param;
		}
		break;
	}
	return ps->deposit;
}

/**
 *	@brief	貯金アイテム購入済みフラグ操作
 */
void PMTelSv_PerchaseFinishFlagSet(PMTEL_SAVE* ps,u8 id)
{
	if(id >= PMTEL_EMBEZZLE_ITEM_MAX ){
		return;
	}
	ps->purchase_finish_f |= (0x0001 << id);
}

/**
 *	@brief	貯金アイテム購入済みフラグ取得
 */
BOOL PMTelSv_PerchaseFinishFlagGet(PMTEL_SAVE* ps,u8 id)
{
	return (ps->purchase_finish_f >> id) & 0x0001;
}

/**
 *	@brief	貯金購入アイテムストック
 */
void PMTelSv_DepositItemStockAdd(PMTEL_SAVE* ps,u16 itemno,u16 num)
{
	int i;

	//空き領域検索して追加
	for(i = 0;i < PMTEL_EMBEZZLE_ITEM_STOCK_MAX;i++){
		if(ps->embezzle_item[i].num == 0){
			ps->embezzle_item[i].itemno = itemno;
			ps->embezzle_item[i].num = num;

			break;
		}
	}
}

/**
 *	@brief	貯金購入アイテムストック削除(先頭から一つ削除)
 */
void PMTelSv_DepositItemStockDel(PMTEL_SAVE* ps)
{
	int i;
	for(i = 0;i < (PMTEL_EMBEZZLE_ITEM_STOCK_MAX-1);i++){
		ps->embezzle_item[i] = ps->embezzle_item[i+1];
	}
	ps->embezzle_item[PMTEL_EMBEZZLE_ITEM_STOCK_MAX-1].itemno = 0;
	ps->embezzle_item[PMTEL_EMBEZZLE_ITEM_STOCK_MAX-1].num = 0;
}

/**
 *	@brief	貯金購入アイテムストック　パラメータ取得
 *
 *	@param	id	ストックID
 *	@param	itemno	アイテムナンバーを格納するバッファポインタ
 *
 *	@return	ストック数(ストック数が0なら無効データ)
 */
u16 PMTelSv_DepositItemStockGet(PMTEL_SAVE* ps,u8 id,u16* itemno)
{
	if(id >= PMTEL_EMBEZZLE_ITEM_STOCK_MAX){
		*itemno = 0;
		return 0;
	}
	*itemno = ps->embezzle_item[id].itemno;
	return ps->embezzle_item[id].num;
}

/**
 *	@brief	ストック領域が満杯かどうか？
 */
BOOL PMTelSv_IsDepositItemStockFull(PMTEL_SAVE* ps)
{
	if(ps->embezzle_item[PMTEL_EMBEZZLE_ITEM_STOCK_MAX-1].num == 0){
		return FALSE;
	}
	return TRUE;
}

/**
 *	@brief	タケノリフラグセット
 */
void PMTelSv_TakenoriFlagSet(PMTEL_SAVE* ps,BOOL set)
{
	ps->takenori_flag = set;
}

/**
 *	@brief	タケノリフラグゲット
 */
BOOL PMTelSv_TakenoriFlagGet(PMTEL_SAVE* ps)
{
	return ps->takenori_flag;
}

/**
 *	@brief	タケノリカウンターを返す
 */
u8 PMTelSv_GetTakenoriCounter(PMTEL_SAVE* ps)
{
	return ps->takenori_ct;
}

/**
 *	@brief	タケノリカウンターをセット
 */
void PMTelSv_SetTakenoriCounter(PMTEL_SAVE* ps,u8 counter)
{
	if(counter > 6){
		counter = 6;
	}
	ps->takenori_ct = counter;
}

/*
 *	@brierf	タケノリカウンターをコントール(日付更新イベントで一日一回だけ呼ぶ)
 */
void PMTelSv_TakenoriCounterControl(PMTEL_SAVE* ps,s32 diff_days)
{
	//タケノリフラグ&タケノリ再戦フラグ&アイテムフラグ強制Off
	ps->takenori_flag = FALSE;
	PMTelSv_ItemEvDataSet(ps,PMTEL_NUMBER_TR_TAKENORI,ITEM_DUMMY_DATA);
	PMTelSv_RevengeFlagSet(ps,PMTEL_NUMBER_TR_TAKENORI,FALSE);

#if 0
	if(ps->takenori_ct > 0){
		ps->takenori_ct--;
	}else{
		ps->takenori_ct = ((gf_rand()%6))+1;
	}
#else
	if((diff_days > 0) && (ps->takenori_ct >= diff_days)){
		ps->takenori_ct -= diff_days;
	}else{	//再抽選
		ps->takenori_ct = ((gf_rand()%6))+1;
	}
#endif
}

/**
 *	@brief	サファリエンカウント率更新履歴保存
 */
void PMTelSv_SafariUpdateHistorySet(PMTEL_SAVE* ps,u8* history,u8 num)
{
	MI_CpuClear8(ps->safari_update,sizeof(u8)*SAFARIL_BLOCK_MAX);
	if(history == NULL){
		ps->safari_update_num = 0;
		return;
	}
	if(num >= SAFARIL_BLOCK_MAX){
		num = SAFARIL_BLOCK_MAX;	//保険で上限チェックしとく
	}
	MI_CpuCopy8(history,ps->safari_update,sizeof(u8)*num);
	ps->safari_update_num = num;
}

/*
 *	@brief	サファリエンカウント率更新履歴取得
 *
 *	@param	num	履歴数を取得するためのu8型変数へのポインタ
 *	@param	heapID	バッファ取得に使用するヒープ
 *
 *	u8型のバッファにエンカウント率更新履歴をAllocして取得します
 *	呼び出し側が解放すること
 */
u8* PMTelSv_SafariUpdateHistoryGetAlloc(PMTEL_SAVE* ps,u8* num,int heapID)
{
	u8* dat = sys_AllocMemory(heapID,sizeof(u8)*ps->safari_update_num);
	MI_CpuCopy8(ps->safari_update,dat,sizeof(u8)*ps->safari_update_num);
	*num = ps->safari_update_num;
	return dat;
}